home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / c-client / os_wsk.c < prev    next >
C/C++ Source or Header  |  1995-09-09  |  16KB  |  545 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- Winsock version
  3.  *
  4.  * Author:    Mike Seibel from Unix version by Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MikeS@CAC.Washington.EDU
  11.  *
  12.  * Date:    11 April 1989
  13.  * Last Edited:    8 September 1995
  14.  *
  15.  * Copyright 1995 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36. /* TCP input buffer -- must be large enough to prevent overflow */
  37.  
  38. #define BUFLEN 8192
  39.  
  40. #include <windows.h>
  41. #define _INC_WINDOWS
  42. #include <winsock.h>
  43.  
  44.  
  45. /* TCP I/O stream (must be before osdep.h is included) */
  46.  
  47. #define TCPSTREAM struct tcp_stream
  48. TCPSTREAM {
  49.   char *host;            /* host name */
  50.   long port;            /* port number */
  51.   char *localhost;        /* local host name */
  52.   SOCKET tcps;            /* tcp socket */
  53.   long ictr;            /* input counter */
  54.   char *iptr;            /* input pointer */
  55.   char ibuf[BUFLEN];        /* input buffer */
  56. };
  57.  
  58.  
  59. /* Private function prototypes */
  60.  
  61. #undef    ERROR            /* quell conflicting def warning */
  62. #include "mail.h"
  63. #include "osdep.h"
  64. #include <time.h>
  65. #include <errno.h>
  66. #include <sys\timeb.h>
  67. #include "misc.h"
  68.  
  69.  
  70. #include "fs_dos.c"
  71. #include "ftl_dos.c"
  72. #include "nl_dos.c"
  73. #include "env_dos.c"
  74.  
  75.  
  76. /* Private functions */
  77.  
  78. long tcp_abort (SOCKET *sock);
  79.  
  80.  
  81. /* Private data */
  82.  
  83. int wsa_initted = 0;        /* init ? */
  84. static int wsa_sock_open = 0;    /* keep track of open sockets */
  85.  
  86.                 /* TCP timeout handler routine */
  87. static tcptimeout_t tcptimeout = NIL;
  88.                 /* TCP timeouts, in seconds */
  89. static long tcptimeout_read = 0;
  90. static long tcptimeout_write = 0;
  91.  
  92. /* TCP/IP manipulate parameters
  93.  * Accepts: function code
  94.  *        function-dependent value
  95.  * Returns: function-dependent return value
  96.  */
  97.  
  98. void *tcp_parameters (long function,void *value)
  99. {
  100.   switch ((int) function) {
  101.   case SET_TIMEOUT:
  102.     tcptimeout = (tcptimeout_t) value;
  103.     break;
  104.   case GET_TIMEOUT:
  105.     value = (void *) tcptimeout;
  106.     break;
  107.   case SET_READTIMEOUT:
  108.     tcptimeout_read = (long) value;
  109.     break;
  110.   case GET_READTIMEOUT:
  111.     value = (void *) tcptimeout_read;
  112.     break;
  113.   case SET_WRITETIMEOUT:
  114.     tcptimeout_write = (long) value;
  115.     break;
  116.   case GET_WRITETIMEOUT:
  117.     value = (void *) tcptimeout_write;
  118.     break;
  119.   default:
  120.     value = NIL;        /* error case */
  121.     break;
  122.   }
  123.   return value;
  124. }
  125.  
  126. /* TCP/IP open
  127.  * Accepts: host name
  128.  *        contact service name
  129.  *        contact port number
  130.  * Returns: TCP/IP stream if success else NIL
  131.  */
  132.  
  133. TCPSTREAM *tcp_open (char *host,char *service,long port)
  134. {
  135.   TCPSTREAM *stream = NIL;
  136.   SOCKET sock;
  137.   char *s;
  138.   struct sockaddr_in sin;
  139.   struct hostent *host_name;
  140.   char tmp[MAILTMPLEN];
  141.   char *hostname = NIL;
  142.   if (!wsa_initted++) {        /* init Windows Sockets */
  143.     WSADATA wsock;
  144.     int     i;
  145.     if (i = (long) WSAStartup (WSA_VERSION,&wsock)) {
  146.       wsa_initted = 0;        /* in case we try again */
  147.       sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
  148.       mm_log (tmp,ERROR);
  149.       return NIL;
  150.     }
  151.   }
  152.   if (s = strchr (host,':')) {    /* port number specified? */
  153.     *s++ = '\0';        /* yes, tie off port */
  154.     port = strtol (s,&s,10);    /* parse port */
  155.     if (s && *s) {
  156.       sprintf (tmp,"Junk after port number: %.80s",s);
  157.       mm_log (tmp,ERROR);
  158.       return NIL;
  159.     }
  160.   }
  161.   /* The domain literal form is used (rather than simply the dotted decimal
  162.      as with other Unix programs) because it has to be a valid "host name"
  163.      in mailsystem terminology. */
  164.   sin.sin_family = AF_INET;    /* family is always Internet */
  165.                 /* look like domain literal? */
  166.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  167.     strcpy (tmp,host+1);    /* yes, copy number part */
  168.     tmp[strlen (tmp)-1] = '\0';
  169.     if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
  170.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  171.       mm_log (tmp,ERROR);
  172.       return NIL;
  173.     }
  174.     else hostname = cpystr (host);
  175.   }
  176.   else {            /* lookup host name */
  177.     if ((host_name = gethostbyname (lcase (strcpy (tmp,host))))) {
  178.                 /* copy host name */
  179.       hostname = cpystr (host_name->h_name);
  180.                 /* copy host addresses */
  181.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  182.     }
  183.     else {
  184.       sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
  185.       mm_log (tmp,ERROR);
  186.       return NIL;
  187.     }
  188.   }
  189.  
  190.                 /* copy port number in network format */
  191.   if (!(sin.sin_port = htons ((u_short)port)))
  192.     fatal ("Bad port argument to tcp_open");
  193.                 /* get a TCP stream */
  194.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
  195.     sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
  196.     mm_log (tmp,ERROR);
  197.     fs_give ((void **) &hostname);
  198.     return NIL;
  199.   }
  200.                 /* open connection */
  201.   if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) == SOCKET_ERROR) {
  202.     switch (WSAGetLastError()) {    /* analyze error */
  203.     case WSAECONNREFUSED:
  204.       s = "Refused";
  205.       break;
  206.     case WSAENOBUFS:
  207.       s = "Insufficient system resources";
  208.       break;
  209.     case WSAETIMEDOUT:
  210.       s = "Timed out";
  211.       break;
  212.     default:
  213.       s = "Unknown error";
  214.       break;
  215.     }
  216.     sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hostname,port,s,
  217.          WSAGetLastError());
  218.     mm_log (tmp,ERROR);
  219.     fs_give ((void **) &hostname);
  220.     return (TCPSTREAM *) tcp_abort (&sock);
  221.   }
  222.                 /* create TCP/IP stream */
  223.   wsa_sock_open++;
  224.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  225.   stream->host = hostname;    /* official host name */
  226.   if(gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR){
  227.       struct sockaddr_in ss;
  228.       int    l = sizeof (struct sockaddr_in);
  229.       if(getsockname (sock,(struct sockaddr *) &ss,&l) != SOCKET_ERROR && l) {
  230.     sprintf (tmp,"[%s]",inet_ntoa (ss.sin_addr));
  231.     stream->localhost = cpystr (tmp);
  232.       }
  233.       else stream->localhost = cpystr ("random-pc");
  234.   }
  235.   else stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
  236.                    host_name->h_name : tmp);
  237.   stream->port = port;        /* port number */
  238.   stream->tcps = sock;        /* init socket */
  239.   stream->ictr = 0;        /* init input counter */
  240.   return stream;        /* return success */
  241. }
  242.   
  243. /* TCP/IP authenticated open
  244.  * Accepts: host name
  245.  *        service name
  246.  *        returned user name
  247.  * Returns: TCP/IP stream if success else NIL
  248.  */
  249.  
  250. TCPSTREAM *tcp_aopen (char *host,char *service,char *usrnam)
  251. {
  252.   return NIL;            /* always NIL on Windows */
  253. }
  254.  
  255. /* TCP/IP receive line
  256.  * Accepts: TCP/IP stream
  257.  * Returns: text line string or NIL if failure
  258.  */
  259.  
  260. char *tcp_getline (TCPSTREAM *stream)
  261. {
  262.   int n,m;
  263.   char *st,*ret,*stp;
  264.   char c = '\0';
  265.   char d;
  266.                 /* make sure have data */
  267.   if (!tcp_getdata (stream)) return NIL;
  268.   st = stream->iptr;        /* save start of string */
  269.   n = 0;            /* init string count */
  270.   while (stream->ictr--) {    /* look for end of line */
  271.     d = *stream->iptr++;    /* slurp another character */
  272.     if ((c == '\015') && (d == '\012')) {
  273.       ret = (char *) fs_get (n--);
  274.       memcpy (ret,st,n);    /* copy into a free storage string */
  275.       ret[n] = '\0';        /* tie off string with null */
  276.       return ret;
  277.     }
  278.     n++;            /* count another character searched */
  279.     c = d;            /* remember previous character */
  280.   }
  281.                 /* copy partial string from buffer */
  282.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  283.                 /* get more data from the net */
  284.   if (!tcp_getdata (stream)) fs_give ((void **) &ret);
  285.                 /* special case of newline broken by buffer */
  286.   else if ((c == '\015') && (*stream->iptr == '\012')) {
  287.     stream->iptr++;        /* eat the line feed */
  288.     stream->ictr--;
  289.     ret[n - 1] = '\0';        /* tie off string with null */
  290.   }
  291.                 /* else recurse to get remainder */
  292.   else if (st = tcp_getline (stream)) {
  293.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  294.     memcpy (ret,stp,n);        /* copy first part */
  295.     memcpy (ret + n,st,m);    /* and second part */
  296.     fs_give ((void **) &stp);    /* flush first part */
  297.     fs_give ((void **) &st);    /* flush second part */
  298.     ret[n + m] = '\0';        /* tie off string with null */
  299.   }
  300.   return ret;
  301. }
  302.  
  303. /* TCP/IP receive buffer
  304.  * Accepts: TCP/IP stream
  305.  *        size in bytes
  306.  *        buffer to read into
  307.  * Returns: T if success, NIL otherwise
  308.  */
  309.  
  310. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  311. {
  312.   unsigned long n;
  313.   char *bufptr = buffer;
  314.   while (size > 0) {        /* until request satisfied */
  315.     if (!tcp_getdata (stream)) return NIL;
  316.     n = min (size,stream->ictr);/* number of bytes to transfer */
  317.                 /* do the copy */
  318.     memcpy (bufptr,stream->iptr,(size_t)n);
  319.     bufptr += n;        /* update pointer */
  320.     stream->iptr +=n;
  321.     size -= n;            /* update # of bytes to do */
  322.     stream->ictr -=n;
  323.   }
  324.   bufptr[0] = '\0';        /* tie off string */
  325.   return T;
  326. }
  327.  
  328.  
  329. /* TCP/IP receive data
  330.  * Accepts: TCP/IP stream
  331.  * Returns: T if success, NIL otherwise
  332.  */
  333.  
  334. long tcp_getdata (TCPSTREAM *stream)
  335. {
  336.   struct timeval timeout;
  337.   int i;
  338.   fd_set fds;
  339.   time_t t = time (0);
  340.   FD_ZERO (&fds);        /* initialize selection vector */
  341.   if (stream->tcps == INVALID_SOCKET) return NIL;
  342.   timeout.tv_sec = tcptimeout_read;
  343.   timeout.tv_usec = 0;
  344.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  345.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  346.                 /* block and read */
  347.     i = select (stream->tcps+1,&fds,0,0,
  348.         timeout.tv_sec ? &timeout : (struct timeval *)0);
  349.     if (i == SOCKET_ERROR){
  350.     if(WSAGetLastError() == WSAEINTR) continue;
  351.     else return tcp_abort(&stream->tcps);
  352.     }
  353.                 /* timeout? */
  354.     else if (i == 0){
  355.       if (tcptimeout && ((*tcptimeout) (time (0) - t))) continue;
  356.       else return tcp_abort (&stream->tcps);
  357.     }
  358.  
  359.     /*
  360.      * recv() replaces read() because SOCKET def's changed and not
  361.      * guaranteed to fly with read().  [see WinSock API doc, sect 2.6.5.1]
  362.      */
  363.     while (((i = recv (stream->tcps,stream->ibuf,BUFLEN,0)) == SOCKET_ERROR) &&
  364.        (WSAGetLastError() == WSAEINTR));
  365.     if (!i || i == SOCKET_ERROR) return tcp_abort(&stream->tcps);
  366.     stream->ictr = i;        /* set new byte count */
  367.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  368.   }
  369.   return T;
  370. }
  371.  
  372. /* TCP/IP send string as record
  373.  * Accepts: TCP/IP stream
  374.  *        string pointer
  375.  * Returns: T if success else NIL
  376.  */
  377.  
  378. long tcp_soutr (TCPSTREAM *stream,char *string)
  379. {
  380.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  381. }
  382.  
  383.  
  384. /* TCP/IP send string
  385.  * Accepts: TCP/IP stream
  386.  *        string pointer
  387.  *        byte count
  388.  * Returns: T if success else NIL
  389.  */
  390.  
  391. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  392. {
  393.   int i;
  394.   struct timeval tmo;
  395.   fd_set fds;
  396.   time_t t = time (0);
  397.   tmo.tv_sec = tcptimeout_write;
  398.   tmo.tv_usec = 0;
  399.   FD_ZERO (&fds);        /* initialize selection vector */
  400.   if (stream->tcps == INVALID_SOCKET) return NIL;
  401.   while (size > 0) {        /* until request satisfied */
  402.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  403.                 /* block and write */
  404.     i = select (stream->tcps+1,NULL,&fds,NULL,
  405.         tmo.tv_sec ? &tmo : (struct timeval *)0);
  406.     if(i == SOCKET_ERROR){
  407.     if(WSAGetLastError() == WSAEINTR) continue;
  408.     else return tcp_abort(&stream->tcps);
  409.     }
  410.                 /* timeout? */
  411.     else if (i == 0){
  412.       if (tcptimeout && ((*tcptimeout) (time (0) - t))) continue;
  413.       else return tcp_abort (&stream->tcps);
  414.     }
  415.  
  416.     /*
  417.      * send() replaces write() because SOCKET def's changed and not
  418.      * guaranteed to fly with write().  [see WinSock API doc, sect 2.6.5.1]
  419.      */
  420.     while (((i = send (stream->tcps,string,(int)size,0)) == SOCKET_ERROR) &&
  421.        (WSAGetLastError() == WSAEINTR));
  422.     if (i == SOCKET_ERROR) return tcp_abort(&stream->tcps);
  423.     size -= i;            /* count this size */
  424.     string += i;
  425.   }
  426.   return T;            /* all done */
  427. }
  428.  
  429.  
  430. /* TCP/IP close
  431.  * Accepts: TCP/IP stream
  432.  */
  433.  
  434. void tcp_close (TCPSTREAM *stream)
  435. {
  436.   tcp_abort (&stream->tcps);    /* nuke the socket */
  437.                 /* flush host names */
  438.   fs_give ((void **) &stream->host);
  439.   fs_give ((void **) &stream->localhost);
  440.   fs_give ((void **) &stream);    /* flush the stream */
  441. }
  442.  
  443.  
  444. /* TCP/IP abort stream
  445.  * Accepts: WinSock SOCKET
  446.  */
  447.  
  448. long tcp_abort (SOCKET *sock)
  449. {
  450.                 /* something to close? */
  451.   if(sock && *sock != INVALID_SOCKET){
  452.     closesocket(*sock);        /* WinSock socket close */
  453.     *sock = INVALID_SOCKET;
  454.                 /* no more open streams? */
  455.     if(wsa_initted && !--wsa_sock_open){
  456.       wsa_initted = 0;        /* no more sockets, so... */
  457.       WSACleanup();        /* free up resources until needed */
  458.     }
  459.   }
  460.   return NIL;
  461. }
  462.  
  463. /* TCP/IP get host name
  464.  * Accepts: TCP/IP stream
  465.  * Returns: host name for this stream
  466.  */
  467.  
  468. char *tcp_host (TCPSTREAM *stream)
  469. {
  470.   return stream->host;        /* return host name */
  471. }
  472.  
  473.  
  474. /* TCP/IP return port for this stream
  475.  * Accepts: TCP/IP stream
  476.  * Returns: port number for this stream
  477.  */
  478.  
  479. long tcp_port (TCPSTREAM *stream)
  480. {
  481.   return stream->port;        /* return port number */
  482. }
  483.  
  484.  
  485. /* TCP/IP get local host name
  486.  * Accepts: TCP/IP stream
  487.  * Returns: local host name
  488.  */
  489.  
  490. char *tcp_localhost (TCPSTREAM *stream)
  491. {
  492.   return stream->localhost;    /* return local host name */
  493. }
  494.  
  495. /* Return my local host name
  496.  * Returns: my local host name
  497.  */
  498.  
  499. char *mylocalhost (void)
  500. {
  501.   if(!myLocalHost){
  502.     char   tmp[MAILTMPLEN];
  503.     struct hostent *host_name;
  504.  
  505.     if (!wsa_initted++) {        /* init Windows Sockets */
  506.       WSADATA wsock;
  507.       int     i;
  508.       if (i = (long)WSAStartup (WSA_VERSION,&wsock)) {
  509.     wsa_initted = 0;
  510.     return(NULL);        /* try again later? */
  511.       }
  512.     }
  513.  
  514.     /* Winsock is rather limited.  We can only call gethostname(). */
  515.     if (gethostname(tmp, MAILTMPLEN-1) == SOCKET_ERROR) {
  516.       /*
  517.        * Nothing's easy.  Since winsock can't gethostid, we'll
  518.        * try faking it with getsocknam().  There's *got* to be
  519.        * a better way than this...
  520.        */
  521.       int    l = sizeof(struct sockaddr_in);
  522.       SOCKET sock;
  523.       struct sockaddr_in sin, stmp;
  524.       sin.sin_family      = AF_INET;    /* family is always Internet */
  525.       sin.sin_addr.s_addr = inet_addr("127.0.0.1");
  526.       sin.sin_port        = htons((u_short)7);
  527.  
  528.       if ((sock = socket(sin.sin_family, SOCK_DGRAM, 0)) != INVALID_SOCKET
  529.       && getsockname(sock,(struct sockaddr *)&stmp,&l) != SOCKET_ERROR
  530.       && l > 0)
  531.     sprintf(tmp,"[%s]",inet_ntoa (stmp.sin_addr));
  532.       else
  533.     strcpy(tmp, "random-pc");
  534.  
  535.       if(sock != INVALID_SOCKET)
  536.     closesocket(sock);    /* leave wsa_initted to save work later */
  537.     }
  538.                     /* canonicalize it */
  539.     else if(host_name = gethostbyname (tmp))
  540.       sprintf(tmp,"%.*s", MAILTMPLEN-1,host_name->h_name);
  541.     myLocalHost = cpystr(tmp);
  542.   }
  543.   return myLocalHost;
  544. }
  545.